package com.zhoug.player.vlcplayer;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.view.Surface;
import android.view.TextureView;

import com.zhoug.player.core.BaseZPlayer;
import com.zhoug.player.core.PlayError;
import com.zhoug.player.core.utils.LogUtils;
import com.zhoug.player.core.utils.ThreadUtils;
import com.zhoug.player.core.utils.Utils;

import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
import org.videolan.libvlc.interfaces.IVLCVout;

import java.io.File;
import java.util.Locale;

import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @author: zhoug
 * @since: 2025-08-11
 */
public class VLCPlayer extends BaseZPlayer {
    private static final String TAG = ">>>VLCPlayer";

    private static final TimePrinter TIME_PRINTER = new TimePrinter();

    /**
     * 每500毫秒更新一次播放进度
     */
    private static final long PROGRESS_UPDATE_INTERVAL = 500;
    private final Handler mainHandler = new Handler(Looper.getMainLooper());
    private LibVLC libVLC;
    private MediaPlayer mediaPlayer;
    private int mWith, mHeight;

    private String recordPath;//录像地址
    private volatile boolean isRecording;//标记正在录像
    private volatile boolean isVideoReady = false;//标记首屏已经加载出来了

    // 操作意图常量
    private static final int OP_NONE = 0;//没有任何操作
    private static final int OP_CREATE_PLAYER = 2;//创建播放器
    private static final int OP_PLAY = 3;//播放
    private static final int OP_PAUSE = 4;//暂停
    private static final int OP_STOP = 5;//停止
    private static final int OP_RELEASE = 8;//释放资源

    private volatile int mCurrentOption = OP_NONE;//当前的意图操作

    private HandlerThread backgroundThread;
    private Handler backgroundHandler;


    public VLCPlayer(Context context) {
        this(context, null);
    }

    public VLCPlayer(Context context, VLCManager.LibVLCWrapper libVLCWrapper) {
        this.mContext = context;
        initBackgroundThread();
        if (libVLCWrapper == null) {
            //初始化LibVLC
            VLCManager.init(context, new VLCManager.Callback() {
                @Override
                public void onSuccess() {
                    VLCManager.LibVLCWrapper instance = VLCManager.getInstance();
                    if (instance != null) {
                        //libVLC初始化成功
                        libVLC = instance.get();
                        if (!isReleased()) {
                            sendOption(OP_CREATE_PLAYER);
                        }
                    } else {
                        callError(PlayError.PLAYER_INIT_FAILURE);
                    }
                }

                @Override
                public void onFailure(String error) {
                    callError(PlayError.PLAYER_INIT_FAILURE, error);
                }
            });
        } else {
            libVLC = libVLCWrapper.get();
            if (!isReleased()) {
                sendOption(OP_CREATE_PLAYER);
            }
        }
    }

    /**
     * 初始化后台线程
     */
    private void initBackgroundThread() {
        backgroundThread = new HandlerThread("VLC-PlayerThread");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case OP_CREATE_PLAYER:
                        if (!isReleased()) {
                            //只要没有触发释放资源的操作就一定会创建播放器,播放器只会创建一次
                            _createMediaPlayer();
                            if (mCurrentOption == OP_PLAY) {
                                _play();
                            }
                        }
                        break;
                    case OP_PLAY://开始播放
                        LogUtils.d(TAG, "handleMessage:OP_PLAY");
                        if (mCurrentOption == OP_PLAY) {
                            _play();
                        }
                        break;
                    case OP_PAUSE://暂停
                        LogUtils.d(TAG, "handleMessage:OP_PAUSE");
                        if (mCurrentOption == OP_PAUSE) {
                            _pause();
                        }
                        break;
                    case OP_STOP://停止
                        LogUtils.d(TAG, "handleMessage:OP_STOP");
                        if (mCurrentOption == OP_STOP) {
                            _stop();
                        }
                        break;
                    case OP_RELEASE://释放资源
                        LogUtils.d(TAG, "handleMessage:OP_RELEASE");
                        if (mCurrentOption == OP_RELEASE) {
                            _release();
                        }
                        break;

                }
            }
        };

    }

    /**
     * 发送当前需要执行的操作
     *
     * @param option
     */
    private synchronized void sendOption(int option) {
        if (backgroundHandler == null || isReleased()) return;
        mCurrentOption = option;
        if (option == OP_RELEASE) {
            //清楚其它全部消息
            backgroundHandler.removeMessages(OP_CREATE_PLAYER);
            backgroundHandler.removeMessages(OP_PLAY);
            backgroundHandler.removeMessages(OP_PAUSE);
            backgroundHandler.removeMessages(OP_STOP);
        }
        Message message = backgroundHandler.obtainMessage();
        message.what = option;
        backgroundHandler.sendMessage(message);
        LogUtils.d(TAG, "sendOption:" + getOptionName(option));

    }


    /**
     * 创建mediaPlayer实例
     */
    private void _createMediaPlayer() {
        try {
            if (mediaPlayer != null) return;
            if (libVLC == null) {
                LogUtils.e(TAG, "createMediaPlayer:libVLC 未初始化");
                return;
            }
            TIME_PRINTER.start("开始创建mediaPlayer实例");
            mediaPlayer = new MediaPlayer(libVLC);
            TIME_PRINTER.print("创建mediaPlayer实例成功");
            setupMediaPlayerListeners();
            mainHandler.post(() -> {
                _bindVideoSurface();
            });
            printPlayerState();
        } catch (Exception e) {
            callError(PlayError.PLAYER_INIT_FAILURE, e.getMessage());
        }
    }

    /**
     * 设置播放监听器
     */
    private void setupMediaPlayerListeners() {
        if (mediaPlayer == null) return;
        mediaPlayer.setEventListener(event -> {
//            LogUtils.d(TAG, "onEvent:"+event.type);
            switch (event.type) {
                case MediaPlayer.Event.Opening://当媒体开始打开（准备播放）但还未开始播放时触发
                    LogUtils.d(TAG, "onEvent Opening");
//                    setPlayerState(STATE_START);
                    callStatusChange(STATE_START);
                    break;
                case MediaPlayer.Event.Buffering://当播放器正在缓冲数据时触发。通常发生在网络流媒体播放时。
                    float buffering = event.getBuffering();
//                    LogUtils.d(TAG, "onEvent Buffering:" + buffering);

                    break;
                case MediaPlayer.Event.Playing://当媒体开始播放（或从暂停状态恢复播放）时触发。
                    LogUtils.d(TAG, "onEvent Playing ");
                    if (isVideoReady) {
                        callVideoOutput();
                    }
                    callStatusChange(STATE_PLAYING);
                    startProgressUpdates();
                    break;
                case MediaPlayer.Event.Paused://当媒体被暂停时触发
                    LogUtils.d(TAG, "onEvent Paused ");
                    callStatusChange(STATE_PAUSE);
                    stopProgressUpdates();
                    break;
                case MediaPlayer.Event.Stopped://当媒体停止播放时触发（例如，调用停止方法后）。
                    LogUtils.d(TAG, "onEvent Stopped ");
                    isVideoReady = false;
                    callStatusChange(STATE_STOP);
                    stopProgressUpdates();
                    break;
                case MediaPlayer.Event.EndReached://当媒体播放到达末尾时触发
                    LogUtils.d(TAG, "onEvent EndReached");
                    isVideoReady = false;
                    callStatusChange(STATE_ENDED);
                    stopProgressUpdates();
                    break;
                case MediaPlayer.Event.EncounteredError://当播放过程中遇到错误时触发。
                    LogUtils.d(TAG, "onEvent EncounteredError");
                    isVideoReady = false;
                    callError(PlayError.PLAYING_ENCOUNTERED_ERROR);
//                    _stop();
                    break;
                case MediaPlayer.Event.Vout://当视频输出（video output）改变时触发。例如，视频轨道变化或者视频输出设备改变。
                    LogUtils.d(TAG, "onEvent Vout VoutCount=" + event.getVoutCount());
                    if (event.getVoutCount() > 0) {
                        isVideoReady = true;
                        callVideoOutput();
                       /* int width = mediaPlayer.getVideoWidth();
                        int height = mediaPlayer.getVideoHeight();
                        if (width > 0 && height > 0 && playListener != null) {
                            mainHandler.post(() -> playListener.onVideoSizeChanged(width, height));
                        }*/
                    }
                    break;
                case MediaPlayer.Event.TimeChanged:
//                    LogUtils.d(TAG, "onEvent TimeChanged: " + getCurrentPosition());
                    break;
                case MediaPlayer.Event.PositionChanged:
//                    LogUtils.d(TAG, "onEvent PositionChanged: " + event.getPositionChanged());
                    break;
                case MediaPlayer.Event.ESAdded:
                    LogUtils.d(TAG, "onEvent ESAdded");
                    break;
                case MediaPlayer.Event.ESSelected:
                    LogUtils.d(TAG, "onEvent ESSelected");
                    break;
                case MediaPlayer.Event.RecordChanged://  当录制状态改变时触发。例如，开始录制或停止录制。
                    boolean recording = event.getRecording();
                    String recordFolder = event.getRecordPath();
                    LogUtils.d(TAG, "onEvent RecordChanged:isRecord=" + recording);
                    LogUtils.d(TAG, "onEvent RecordChanged:path=" + recordFolder);
                    //监听停止录像
                    if (isRecording && !recording) {
                        String desPath = recordPath;
                        isRecording = false;
                        recordPath = null;
                        //获取文件地址
                        File file = null;
                        if (!TextUtils.isEmpty(recordFolder)) {
                            File folder = new File(recordFolder);
                            if (folder.exists()) {
                                if (folder.isFile()) {
                                    file = folder;
                                } else {
                                    File[] files = folder.listFiles();
                                    if (files != null && files.length > 0) {
                                        file = files[0];
                                    }
                                }
                            }
                        }
                        if (file == null) {
                            callRecordVideoError("录像失败");
                        } else {
                            if (desPath != null) {
                                File src = file;
                                ThreadUtils.getExecutorService().execute(() -> {
                                    boolean success = Utils.remoteFile(src, new File(desPath));
                                    if (success) {
                                        callRecordVideoStop(desPath);
                                    } else {
                                        callRecordVideoError("处理录像文件失败");
                                    }
                                });
                            } else {
                                callRecordVideoStop(file.getAbsolutePath());
                            }
                        }

                    }

                    break;
            }
        });
    }


    /**
     * 绑定试图
     */
    @MainThread
    private void _bindVideoSurface() {
        if (mTextureView == null) return;
        if (mediaPlayer == null) return;
        setVideoSurface(mTextureView.getSurfaceTexture());
        setWindowSize(mTextureView.getWidth(), mTextureView.getHeight());
        mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                LogUtils.d(TAG, "onSurfaceTextureAvailable");
                setVideoSurface(surface);
                setWindowSize(width, height);

            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                try {
                    if (mediaPlayer != null) {
                        mediaPlayer.getVLCVout().detachViews();
                    }
                } catch (Exception e) {
                    LogUtils.e(TAG, "onSurfaceTextureDestroyed:" + e.getMessage());
                }
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

            }
        });
        mTextureView.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
            // 获取新的宽度和高度
            LogUtils.d(TAG, "TextureView OnLayoutChangeListener");
            int w = right - left;
            int h = bottom - top;
            setWindowSize(w, h);
        });
    }

    /**
     * 设置窗口
     *
     * @param surfaceTexture
     */
    private void setVideoSurface(SurfaceTexture surfaceTexture) {
        if (mediaPlayer == null) return;
        if (surfaceTexture == null) {
            return;
        }
        LogUtils.d(TAG, "setVideoSurface:");
//        mediaPlayer.getVLCVout().setVideoSurface(surfaceTexture);
//        mediaPlayer.getVLCVout().attachViews();
        Surface surface = new Surface(surfaceTexture);
        IVLCVout vlcVout = mediaPlayer.getVLCVout();
        vlcVout.setVideoSurface(surface, null);
        vlcVout.attachViews();

    }


    /**
     * 设置播放窗口大小
     *
     * @param width
     * @param height
     */
    @MainThread
    private void setWindowSize(int width, int height) {
        if (mediaPlayer == null) return;
        // 设置VLC播放器的宽高参数
        if (width > 0 && height > 0 && mWith != width && mHeight != height) {
            mWith = width;
            mHeight = height;
            if (mRenderMode == RENDER_MODE_FULL_FILL_SCREEN) {
                mediaPlayer.getVLCVout().setWindowSize(width, height);
                //下面2行代码 设置充满屏幕否则有黑边
                mediaPlayer.setAspectRatio(width + ":" + height);
                mediaPlayer.setScale(0);
            } else {
                mediaPlayer.getVLCVout().setWindowSize(width, height);
            }
            LogUtils.d(TAG, "Window width=" + width + ",width=" + height);
        }
    }


    @Override
    public boolean isReleased() {
        return super.isReleased() ;
    }

    private boolean libVLCIsReleased() {
        return libVLC != null && libVLC.isReleased();
    }

    /**
     * 开始播放
     */
    private void _play() {
        if (isReleased() || mediaPlayer == null) return;
        if (TextUtils.isEmpty(mPlayUrl)) {
            callError(PlayError.URL_IS_EMPTY);
            return;
        }
        printPlayerState();
        int playSate = getPlaySate();
        //已经开始,正在播放 则跳过操作
        if (playSate == STATE_START || playSate == STATE_PLAYING) {
            return;
        }
        //需要初始化设置媒体资源
        if (playSate == STATE_IDLE || playSate == STATE_STOP || playSate == STATE_ENDED) {
            try {
                isVideoReady = false;
                TIME_PRINTER.start("setMedia");
                Media media = new Media(libVLC, Uri.parse(mPlayUrl));
                media.setHWDecoderEnabled(false, false);//设置后才可以录制和截屏,这行必须放在mMediaPlayer.setMedia(media)后面，因为setMedia会设置setHWDecoderEnabled为true
                mediaPlayer.setMedia(media);
                media.release();
                TIME_PRINTER.print("setMedia");
            } catch (Exception e) {
                callError(PlayError.MEDIA_ERROR, e.getMessage());
                return;
            }
        }
        try {
            TIME_PRINTER.start("play 开始播放");
            mediaPlayer.play();
            TIME_PRINTER.print("play 开始播放");
            callStatusChange(STATE_START);
        } catch (Exception e) {
            callError(PlayError.PLAY_ERROR, e.getMessage());
        }
    }


    /**
     * 暂停播放
     */
    private void _pause() {
        if (isReleased() || mediaPlayer == null) return;
        int playSate = getPlaySate();
        if (playSate == STATE_START || playSate == STATE_PREPARED || playSate == STATE_PLAYING) {
            try {
                TIME_PRINTER.start("pause 暂停播放");
                printPlayerState();
                mediaPlayer.pause();
                TIME_PRINTER.print("pause 暂停播放");
                callStatusChange(STATE_PAUSE);
            } catch (Exception e) {
                LogUtils.e(TAG, "pause 暂停播放发生错误:" + e.getMessage());
            }
        }
    }

    /**
     * 停止播放 必须在线程中执行 耗时普遍超出16毫秒,有时超过2秒了
     */
    private void _stop() {
        if (null == mediaPlayer) return;
        if (isReleased() || mediaPlayer == null) return;
        int playSate = getPlaySate();
        if (playSate == STATE_START || playSate == STATE_PREPARED || playSate == STATE_PLAYING || playSate == STATE_PAUSE) {
            try {
                isVideoReady = false;
                TIME_PRINTER.start("stop 停止播放");
                printPlayerState();
                mediaPlayer.stop();
                TIME_PRINTER.print("stop 停止播放");
                callStatusChange(STATE_STOP);
            } catch (Exception e) {
                LogUtils.e(TAG, "stop 停止播放发生错误:" + e.getMessage());
            }
        }


    }

    /**
     * 释放资源 必须在线程中执行耗时最高达到16秒
     */
    private void _release() {
        if (null == mediaPlayer) return;
        try {
            isVideoReady = false;
            TIME_PRINTER.start("release 开始释放资源");
            printPlayerState();
            mediaPlayer.release();
            TIME_PRINTER.print("release 释放资源");
            callStatusChange(STATE_IDLE);
            if (backgroundThread != null) {
                backgroundThread.quitSafely();
                try {
                    backgroundThread.join();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                backgroundThread = null;
                backgroundHandler = null;
            }
        } catch (Exception e) {
            LogUtils.e(TAG, "release 释放资源发生错误:" + e.getMessage());
        }
    }


    /**
     * 设置静音
     */
    private void _setMute() {
        if (mediaPlayer != null) {
            int volume = mediaPlayer.getVolume();
            if (mMute && volume != 0) {
                mediaPlayer.setVolume(0);
            } else if (!mMute && volume != 100) {
                mediaPlayer.setVolume(100);
            }
        }
    }


    @Override
    public void setVideoTextureView(@Nullable TextureView textureView) {
        super.setVideoTextureView(textureView);
        _bindVideoSurface();
    }


    @Override
    public void startPlay() {
        if (isReleased()) return;
        sendOption(OP_PLAY);
    }

    @Override
    public void resumePlay() {
        if (isReleased()) return;
        sendOption(OP_PLAY);
    }

    @Override
    public void pausePlay() {
        if (isReleased()) return;
        sendOption(OP_PAUSE);
    }


    @Override
    public void stopPlay() {
        if (isReleased()) return;
        sendOption(OP_STOP);
    }

    @Override
    public void release() {
        sendOption(OP_RELEASE);
        super.release();
    }

    /**
     * 是否支持设置播放进度
     *
     * @return
     */
    public boolean isSeekAble() {
        return mediaPlayer != null && mediaPlayer.isSeekable();
    }

    @Override
    public void seekTo(long positionMs) {
        if (isSeekAble()) {
            mediaPlayer.setTime(positionMs);
        }
    }

    @Override
    public void setMute(boolean mute) {
        super.setMute(mute);
        _setMute();
    }


    @Override
    public boolean isRecording() {
        return isRecording;
    }

    @Override
    public void startRecordVideo(String path) {
        if (isRecording || mediaPlayer == null || !isPlaying()) return;
        recordPath = path;
        isRecording = true;
        try {
            TIME_PRINTER.start("正在启动录像");
            //设置的文件目录不一定使用,播放器没有释放的情况下有可能一直都使用的是第一次设置的文件夹,所有最好固定文件夹
            File folder = new File(new File(path).getParent(), "vlcRecordDirs");
            if (!folder.exists()) {
                if (!folder.mkdirs()) {
                    isRecording = false;
                    recordPath = null;
                    callRecordVideoError("创建录像文件存储目录失败");
                    return;
                }
            }
            LogUtils.d(TAG, "startRecordVideo:" + folder.getAbsolutePath());
            isRecording = mediaPlayer.record(folder.getAbsolutePath());
            TIME_PRINTER.print("启动录像:" + (isRecording ? "成功" : "失败"));
            if (isRecording) {
                callRecordVideoStart();
            } else {
                recordPath = null;
                callRecordVideoError("启动录像失败");
            }

        } catch (Exception e) {
            TIME_PRINTER.print("启动录像失败");
            isRecording = false;
            recordPath = null;
            callRecordVideoError("启动录像失败" + e.getMessage());
        }
    }

    @Override
    public void stopRecordVideo() {
        if (!isRecording || mediaPlayer == null) return;
        try {
            TIME_PRINTER.start("正在停止录像");
            mediaPlayer.record(null);
            TIME_PRINTER.print("停止录像");
//            final String path = recordPath;
//            callRecordVideoStop(path);
        } catch (Exception e) {
            TIME_PRINTER.print("停止录像失败");
            LogUtils.e(TAG, "停止录像失败:" + e.getMessage());
            recordPath = null;
            callRecordVideoError(e.getMessage());

        }

    }

    @Deprecated
    @Override
    public void startVoiceTalk() {

    }

    @Deprecated
    @Override
    public void stopVoiceTalk() {

    }

    @Deprecated
    @Override
    public boolean isTalking() {
        return false;
    }

    @Override
    public long getCurrentPosition() {
        return mediaPlayer != null ? mediaPlayer.getTime() : 0;
    }

    @Override
    public long getDuration() {
        return mediaPlayer != null ? mediaPlayer.getLength() : 0;
    }

    /**
     * 开启播放进度更新
     */
    private void startProgressUpdates() {
        stopProgressUpdates();
        if (mPlayProgressListener == null) return;
        mainHandler.postDelayed(progressUpdateRunnable, PROGRESS_UPDATE_INTERVAL);
    }

    /**
     * 停止播放进度更新
     */
    private void stopProgressUpdates() {
        mainHandler.removeCallbacks(progressUpdateRunnable);
    }

    /**
     * 播放进度更新任务
     */
    private final Runnable progressUpdateRunnable = new Runnable() {
        @Override
        public void run() {
            if (mPlayProgressListener != null && mediaPlayer != null && mPlayState == STATE_PLAYING) {
                long position = getCurrentPosition();
                long duration = getDuration();
                mPlayProgressListener.onPositionChange(position);
                mPlayProgressListener.onDurationChange(duration);
            }
            mainHandler.postDelayed(this, PROGRESS_UPDATE_INTERVAL);
        }
    };

    private void printPlayerState() {
//        if (isReleased() || mediaPlayer == null) return;
//        String stateName = VLCPlayerState.getStateName(mediaPlayer.getPlayerState());
//        LogUtils.d(TAG, "mediaPlayerState:" + stateName);
    }

    private String getOptionName(int option) {
        return switch (option) {
            case OP_NONE -> "OP_NONE";
            case OP_CREATE_PLAYER -> "OP_CREATE_PLAYER";
            case OP_PLAY -> "OP_PLAY";
            case OP_PAUSE -> "OP_PAUSE";
            case OP_STOP -> "OP_STOP";
            case OP_RELEASE -> "OP_RELEASE";
            default -> "";
        };
    }

    private static class TimePrinter {
        private long _startTime;

        public void start() {
            start(null);
        }

        public void start(String msg) {
            _startTime = System.currentTimeMillis();
            if (msg != null) {
                LogUtils.d(TAG, msg);
            }
        }

        public void print(String tag) {
            long times = (System.currentTimeMillis() - _startTime);
            String msg = String.format(Locale.CHINA, "thread:%s,%s,耗时:%d", Thread.currentThread().getName(),tag, times);
            if (times < 16) {
                LogUtils.d(TAG, msg);
            } else if (times < 100) {
                LogUtils.w(TAG, msg);
            } else {
                LogUtils.e(TAG, msg);
            }
        }
    }


}
